package github.sf.fw.utils;

import java.math.BigDecimal;
import java.math.RoundingMode;

/**
 * 存储单位换算工具类
 */
public class StoreUnitUtil {
    private final static int N = 1024;
    private static final CapacityUnit BASE_UNIT_TYPE = CapacityUnit.MB;

    public static strictfp double getKb(long bit) {
        return divide(bit, 1024).doubleValue();
    }

    public static strictfp double getMb(long bit) {
        return divide(bit, Math.pow(1024, 2)).doubleValue();
    }

    public static strictfp double getGb(long bit) {
        return divide(bit, Math.pow(1024, 3)).doubleValue();
    }

    public static strictfp double div1024(double v) {
        return divide(v, 1024).doubleValue();
    }

    public static String humanRead(long bit) {
        double kb = getKb(bit);
        if (kb < N) {
            return kb + "KB";
        }
        double mb = div1024(kb);
        if (mb < N) {
            return mb + "MB";
        }
        double gb = div1024(mb);
        if (gb < N) {
            return gb + "GB";
        }
        double tb = div1024(mb);
        return tb + "TB";
    }

    public static String humanReadFromKb(double kb) {
        if (kb < N) {
            return kb + "KB";
        }
        double mb = div1024(kb);
        if (mb < N) {
            return mb + "MB";
        }
        double gb = div1024(mb);
        if (gb < N) {
            return gb + "GB";
        }
        double tb = div1024(gb);
        return tb + "TB";
    }

    public static String humanReadFromMb(double mb) {
        if (mb < N) {
            return mb + "MB";
        }
        double gb = div1024(mb);
        if (gb < N) {
            return gb + "GB";
        }
        double tb = div1024(gb);
        return tb + "TB";
    }

    public static String humanReadFromGb(double gb) {
        if (gb < N) {
            return gb + "GB";
        }
        double tb = div1024(gb);
        return tb + "TB";
    }

    /**
     * 安全除法
     */
    public static BigDecimal divide(Number a, Number b) {
        BigDecimal n1;
        BigDecimal n2;
        if (a instanceof BigDecimal) {
            n1 = (BigDecimal) a;
        } else {
            n1 = BigDecimal.valueOf(a.doubleValue());
        }
        if (b instanceof BigDecimal) {
            n2 = (BigDecimal) b;
        } else {
            n2 = BigDecimal.valueOf(b.doubleValue());
        }
        return n1.divide(n2, 2, RoundingMode.HALF_UP);
    }

    public static BigDecimal unitTransfer(Number val, CapacityUnit fromUnit, CapacityUnit toUnit) {
        BigDecimal baseUnitVal = toBaseUnit(val, fromUnit);
        return mbToTarget(baseUnitVal, toUnit);
    }

    public static BigDecimal mbToTarget(Number val, CapacityUnit targetUnit) {
        switch (targetUnit) {
            case B:
                return BigDecimal.valueOf(val.doubleValue() * Math.pow(1024, 2));
            case KB:
                return BigDecimal.valueOf(val.doubleValue() * 1024);
            case MB:
                return BigDecimal.valueOf(val.doubleValue());
            case GB:
                return divide(val, 1024);
            case TB:
                return divide(val, Math.pow(1024, 2));
            default:
                break;
        }
        return BigDecimal.ZERO;
    }

    public static BigDecimal toBaseUnit(Number val, CapacityUnit fromUnit) {
        BigDecimal baseUnitVal = BigDecimal.ZERO;
        switch (fromUnit) {
            case B:
                return divide(val, Math.pow(1024, 2));
            case KB:
                return divide(val, Math.pow(1024, 1));
            case MB:
                return BigDecimal.valueOf(val.doubleValue());
            case GB:
                return BigDecimal.valueOf(val.doubleValue() * 1024);
            case TB:
                return BigDecimal.valueOf(val.doubleValue() * Math.pow(1024, 2));
            default:
                break;
        }
        return baseUnitVal;
    }

    public static NumberUnit parseToNumberUnit(String numStr) {
        char[] chars = numStr.toCharArray();
        StringBuilder suffix = new StringBuilder();
        boolean meetNumber = false;
        int index = -1;
        for (int i = 0; i < numStr.toCharArray().length; i++) {
            char ch = numStr.toCharArray()[i];
            if (Character.isDigit(ch) || ch == '.') {
                meetNumber = true;
            } else {
                if (index == -1) {
                    index = i;
                }
                if (meetNumber) {
                    suffix.append(ch);
                }
            }
        }
        if (index == -1) {
            Double aDouble = Double.valueOf(numStr);
            return new NumberUnit(aDouble, numStr);
        } else {
            String substring = numStr.substring(0, index);
            double aDouble = Double.parseDouble(substring);
            return new NumberUnit(aDouble, suffix.toString());
        }
    }


    /**
     * 存储容量单位
     */
    public enum CapacityUnit {
        /**
         * 容量单位
         */
        B, KB, MB, GB, TB
    }

    public static class NumberUnit {
        public double val;
        public String unit;

        public NumberUnit(double val, String unit) {
            this.val = val;
            this.unit = unit;
        }

        public NumberUnit() {
        }

        public CapacityUnit getCapacityUnit() {
            if (unit == null || "".equals(unit.trim())) {
                return null;
            }
            for (CapacityUnit capacityUnit : CapacityUnit.values()) {
                if (capacityUnit.name().equals(unit.trim().toUpperCase()) ||
                        capacityUnit.name().equals(unit.trim().toUpperCase() + "B")) {
                    return capacityUnit;
                }
            }
            return null;
        }

        @Override
        public String toString() {
            return "NumberUnit{" +
                    "val=" + val +
                    ", unit='" + unit + '\'' +
                    '}';
        }
    }

}
